#ifndef PW_PBL_IITERATOR_HPP
#define PW_PBL_IITERATOR_HPP

#include "Interface.hpp"

namespace pw_pbl
{
	namespace _iterator
	{
		template <typename VALUE>
		struct Writer
		{
			using _tValueParm = std::conditional_t<sizeof(VALUE) <= sizeof(nullptr), VALUE, VALUE &&>;
			void *pObj;
			void (*pWrite)(_tValueParm v);

			constexpr void operator=(_tValueParm v) { pWrite(pObj, std::forward<_tValueParm>(v)); };
		};

		template <typename VALUE>
		struct WriterWithNext
		{
			using _tValueParm = std::conditional_t<sizeof(VALUE) <= sizeof(nullptr), VALUE, VALUE &&>;
			void *pObj;
			void (*pWrite)(void *, _tValueParm v);
			void (*pNext)(void *);

			constexpr void operator=(_tValueParm v)
			{
				pWrite(pObj, std::forward<_tValueParm>(v));
				pNext(pObj);
				pNext = nullptr;
			};
			inline ~WriterWithNext()
			{
				if (pNext != nullptr)
					pNext(pObj);
			}
		};

		template <typename VALUE>
		struct DelayNext
		{
			WriterWithNext<VALUE> nexter;
			WriterWithNext<VALUE> &operator*() noexcept { return nexter; }
		};

		template <typename VALUE>
		struct Output
		{
			using _tValueParm = std::conditional_t<sizeof(VALUE) <= sizeof(nullptr), VALUE, VALUE &&>;
			void *pObj;
			void (*pWrite)(void *, _tValueParm v);
			void (*pNext)(void *);

			using iterator_category = std::output_iterator_tag;
			using value_type = void;
			using difference_type = std::ptrdiff_t;
			using pointer = void;
			using reference = void;

			constexpr Output &operator++() noexcept { return pNext(pObj), *this; }

			constexpr Writer<VALUE> operator*() noexcept { return {.pObj{pObj}, .pWrite{pWrite}}; }

			constexpr DelayNext<VALUE> operator++(int) noexcept
			{
				return {.nexter{.pObj{pObj}, .pWrite{pWrite}, .pNext{pNext}}};
			}
		};
	} // namespace _iterator

	/// 输出迭代器接口
	/// @tparam VALUE 可输出的值类型
	template <typename VALUE>
	class IOutputIterator : public Interface::TBox<IOutputIterator<VALUE>>
	{
		using _tBox = Interface::TBox<IOutputIterator>;
		using _tBox::_tBox;
		using _tValueParm = std::conditional_t<sizeof(VALUE) <= sizeof(nullptr), VALUE, VALUE &&>;

	public:
		struct TRawVTable
		{
			Interface::TStaticVFunc<void(_tValueParm)> *write;
			Interface::TStaticVFunc<void(void)> *next;
		};

		template <typename _tSelf>
		class TRawRef
		{
		protected:
			TRawRef() = default;
			TRawRef(const TRawRef &) = default;
			TRawRef(TRawRef &&) = default;

		public:
			inline _iterator::Output<VALUE> get() noexcept
			{
				Interface::TPtr<IOutputIterator> ptr{*(_tSelf *)this};
				return {.pObj{ptr.pObj()}, .pWrite{ptr.VTable().write}, .pNext{ptr.VTable().next}};
			}
		};

		template <typename _tObj>
		static constexpr bool CanFrom = std::output_iterator<_tObj, VALUE>;

		template <typename _tObj>
		static constexpr std::tuple<> ClassVTable{};

		template <typename _tObj>
		requires CanFrom<_tObj>
		static constexpr TRawVTable ClassVTable<_tObj>{
			.write = [](void *pObj, _tValueParm v) { *(*(_tObj *)pObj) = std::forward<_tValueParm>(v); },
			.next = [](void *pObj) { ++(*(_tObj *)pObj); },
		};
	};
} // namespace pw_pbl
#endif // PW_PBL_IITERATOR_HPP
